#include "nenginesession.h"
#include <time.h>

//pcap文件格式[文件头][数据头1][数据包1][数据头2][数据包2]....
typedef struct
{
	uint32_t magic;//魔术值
	uint16_t version_major;//主版本号0x2
	uint16_t version_minor;//副版本号0x4
	uint32_t thiszone;//区域时间（实际无用）
	uint32_t sigfigs;//精确时间戳（实际无用）
	uint32_t snaplen;//数据包最大长度
	uint32_t linktype;//链路层类型（常用为以太网）
} pcap_file_header;
//pcap数据包头结构
typedef struct
{
	struct timeval ts;//时间戳
	uint32_t caplen;//当前分组长度
	uint32_t len;//数据包长度
} pcap_pkthdr;

SessionPkgDataManage::SessionPkgDataManage()
{
	//进行初始化
	_sessionBufMap.clear();
	_sessionBufInfoMap.clear();
}

SessionPkgDataManage::~SessionPkgDataManage()
{
	uint8_t *p = NULL;
	hash_map<uint32_t,uint8_t *>::const_iterator _sessionBufMapIt;
	for(_sessionBufMapIt = _sessionBufMap.begin();
		_sessionBufMapIt != _sessionBufMap.end();
							++_sessionBufInfoMapIt) {
		p = _sessionBufMapIt->second;
		freeBuf(p);
	}
	//进行释放
	_sessionBufMapIt.clear();
	_sessionBufInfoMap.clear();
}

bool
SessionPkgDataManage::insertPkgToSession(SessionInfon *sess,packet_t *pkt)
{
	//获取hash值
	uint32_t key_hash = getSessionHash(sess);
	//创建缓冲区保存会话一个文件一个会话，然后是pcap格式
	//首先是根据key_hash看是否是已有会话
	hash_map<uint32_t,uint8_t *>::const_iterator it;
	it = _sessionBufMap.find(key_hash);
	if(it == _sessionBufMap.end()) {
		//说明是新增会话，建立缓存并开始存包
		size_t buf_len = sizeof(pcap_file_header) + \
					sizeof(pcap_pkthdr) + pkt->pk_len;
		//pkt包应该是一个数据帧的所有信息
		buf_len *= 2;
		uint8_t *sess_buf = assignNewMemToBuf(buf_len);
		bufSizeInfo bsi;
		bsi._bufMaxLen = buf_len;
		bsi._bufCurUsedLen = 0;
		//将session的相关信息保存到hash表中
		_sessionBufMap.insert(make_pair(key_hash,sess_buf));
		_sessionBufInfoMap.insert(make_pair(sess_buf,bsi));
	} else {
		//取出缓冲区信息构造数据头和数据包进行追加
		//取出缓冲区，然后是要注意过大，然后是重新
		//分配空间的问题
		//取出缓冲区大小信息然后进行判断，如果插入
		//数据过小，最好提前进行一次resize
		uint8_t *sess_buf = it->second;
		size_t sess_buf_max_len = getBufSize(sess_buf);
		size_t sess_buf_cur_used_len = getBufCurUsedSize(sess_buf);
		size_t sess_buf_unused_len = sess_buf_max_len \
								- sess_buf_cur_used_len;
		if(sess_buf_unused_len < pkt->pk_len) {
			//说明需要重新进行内存分配
			resizeSessionBufSize(sess,sess_buf_max_len * 2);
		}
		//然后进行插入操作，因为迭代器元素可能已经删除了，所以这里重新
		//获取
		it = _sessionBufMap.find(key_hash);
		sess_buf = it->second;
		sess_buf_cur_used_len = getBufCurUsedSize(sess_buf);
		//进行复制操作关键是获取到完整的数据帧，然后复制过去
	}
}
//进行尺寸修改
bool
SessionPkgDataManage::resizeSessionBufSize(SessionInfon *sess,
												size_t buf_len)
{
	//取出缓冲区进行处理
	uint32_t key_hash = getSessionHash(sess);
	hash_map<uint32_t,uint8_t *>::const_iterator it;
	it = _sessionBufMap.find(key_hash);
	if(it != _sessionBufMap.end()) {
		uint8_t *old_buf = it->second;
		uint8_t *buf = resizeBufSize(old_buf,buf_len);
		if(buf != old_buf) {
			//说明进行了修改需要重新进行map的修改
			//_sessionBufInfoMap已经进行了更新
			//这里就对_sessionBufMap进行更新
			_sessionBufMap.erase(it);
			//重新插入
			_sessionBufMap.insert(make_pair(key_hash,buf));
		}
		//尺寸修改完成，返回true
		return true;
	}
	return false;
}

bool
SessionPkgDataManage::deletePkgFromSession(SessionInfon *sess)
{
	//
}

bool
SessionPkgDataManage::flushPkgToRawPcapFile(SessionInfon *sess)
{
	//
}

inline uint32_t
calcSessionHash(void *key)
{
	//进行hash计算将key当做字符串
	//保证最后以\0结束
	char *f_path = (char *)key;
	register uint32_t nr = 1,nr2 = 4;
	while(*f_path++ != '\0') {
		nr ^= ((nr & 63) + nr2) * \
			((uint32_t)(*f_path)) \
					+ (nr << 8);
		nr2 += 3;
	}
	//尽量让key均匀分布
	return (nr % 49999);
}
#define	KEY_BUF_LEN	20
static uint8_t key_buf[KEY_BUF_LEN] = {0};

uint32_t
SessionPkgDataManage::getSessionHash(SessionInfon *sess)
{
	//计算hash值
	//首先根据sess的5元组生成一个hash表key值
	//5元组的大小不超过20
	memset(key_buf,0,KEY_BUF_LEN);
	////////////
	uint32_t key_buf_off = 0;
	memcpy(key_buf + key_buf_off,&(snode->s_packet.sip),
						sizeof(snode->s_packet.sip));
	////////////
	key_buf_off += sizeof(snode->s_packet.sip);
	memcpy(key_buf + key_buf_off,&(snode->s_packet.dip),
						sizeof(snode->s_packet.dip));
	////////////
	key_buf_off += sizeof(snode->s_packet.dip);
	memcpy(key_buf + key_buf_off,&(snode->s_packet.sport),
						sizeof(snode->s_packet.sport));
	////////////
	key_buf_off += sizeof(snode->s_packet.sport);
	memcpy(key_buf + key_buf_off,&(snode->s_packet.dport),
						sizeof(snode->s_packet.dport));
	////////////
	key_buf_off += sizeof(snode->s_packet.dport);
	memcpy(key_buf + key_buf_off,&(snode->s_packet.l4_proto),
						sizeof(snode->s_packet.l4_proto));
	uint32_t key_hash = calcSessionHash(key_buf);
	return key_hash;
}

uint8_t *
SessionPkgDataManage::assignNewMemToBuf(size_t buf_len)
{
	if(buf_len <= 0) {
		return NULL;
	}
	uint8_t *buf = new uint8_t[buf_len]
	memset(buf,0,buf_len);
	return buf;
}

size_t
SessionPkgDataManage::getBufCurUsedSize(uint8_t *buf)
{
	//根据当前的缓冲区找到相关的长度信息
	hash_map<uint32_t,uint8_t *>::const_iterator it;
	it = _sessionBufInfoMap.find(buf);
	if(it != _sessionBufInfoMap.end()) {
		//获取信息
		bufSizeInfo bsi = it->second;
		return bsi._bufCurUsedLen;
	}
	return 0;
}

void
SessionPkgDataManage::freeBuf(uint8_t *buf)
{
	//进行释放
	if(NULL != buf) {
		free(buf);
	}
}

size_t
SessionPkgDataManage::getBufSize(uint8_t *buf)
{
	//根据当前的缓冲区找到相关的长度信息
	hash_map<uint32_t,uint8_t *>::const_iterator it;
	it = _sessionBufInfoMap.find(buf);
	if(it != _sessionBufInfoMap.end()) {
		//获取信息
		bufSizeInfo bsi = it->second;
		return bsi._bufMaxLen;
	}
	return 0;
}

//返回重新分配好的空间并将原缓冲区数据拷贝到新缓冲区中
//主语原缓冲区所对应的session要先取到，这样才能和新的
//空间重新建立对应关系。
uint8_t *
SessionPkgDataManage::resizeBufSize(uint8_t *buf,size_t buf_len)
{
	if(NULL == buf) {
		return 0;
	}
	if(NULL == *buf) {
		return 0;
	}
	if(buf_len <= 0) {
		return -1;
	}
	//要保留以前的数据
	size_t buf_old_len = getBufSize(buf);
	size_t buf_old_cur_len = getBufCurUsedSize(buf);
	bufSizeInfo bsi;
	uint8_t *new_buf = NULL;
	if(buf_old_cur_len > buf_len) {
		//说明数据发生了截断
		bsi._bufCurUsedLen = buf_len;
		new_buf = buf;
	}
	if(buf_old_len > buf_len) {
		//原来的缓冲区足够大只用修改缓冲信息即可
		bsi._bufMaxLen = buf_len;
		new_buf = buf;
	}
	if(buf_old_len < buf_len) {
		//重新分配内存并进行数据转移
		//涉及到匹配会话的问题这个在
		//上层去处理
		new_buf = new uint8_t[buf_len];
		memset(new_buf,0,buf_len);
		memcpy(new_buf,buf,buf_old_cur_len);
		bsi._bufMaxLen = buf_len;
		bsi._bufCurUsedLen = buf_old_cur_len;
	}
	//对信息进行更新
	hash_map<uint32_t,uint8_t *>::const_iterator it;
	if(new_buf != buf) {
		//说明重新分配
		it = _sessionBufInfoMap.find(buf);
		if(it != _sessionBufInfoMap.end()) {
			_sessionBufInfoMap.erase(it);
		}
		delete []buf;
		_sessionBufInfoMap.insert(make_pair(new_buf,bsi));
	} else {
		//说明没有进行重新分配，只更新bsi
		it = _sessionBufInfoMap.find(buf);
		if(it != _sessionBufInfoMap.end()) {
			it->second = bsi;
		}
	}
	return new_buf;
}
